package com.hwh.bootdemoweb.Netty第四章;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static com.hwh.bootdemoweb.ByteBufferUtil.debugAll;
import static com.hwh.bootdemoweb.ByteBufferUtil.debugRead;
/**
 * @author wenhao hu
 * @title: Server
 * @projectName bootdemoweb
 * @description: TODO
 * @date 2021/12/1011:43
 */
public class Server {

    private static void split(ByteBuffer source){
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) == '\n'){
                int length = i+1-source.position();

                ByteBuffer target = ByteBuffer.allocate(length);

                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                debugRead(target);
            }
        }
        source.compact();
    }




    public static void main(String[] args) throws IOException {
        //创建Selector 管理多个Channel
        Selector selector = Selector.open();
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        //建立Selector和Channel的联系，注册channel到Selector
        //SelectionKey:事件发生时通过它可以得到这个事件和哪个channel发送的事件
        SelectionKey sscKey = ssc.register(selector, 0, null);
        //key 只关注accept事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);
        System.out.println("register key:"+sscKey);
        ssc.bind(new InetSocketAddress(8080));
        List<SocketChannel> channels = new ArrayList<>();
        while (true){
            //调用Selector的select方法 线程阻塞，有事件发生时县城才会继续运行
            //select在事件未处理时，他不会阻塞。事件发生后要么处理，要么取消。不能置之不理。
            selector.select();
            //处理事件 selectedKeys内部包含了所有发生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                System.out.println("event key:"+key);
                //区分事件类型
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    SocketChannel sc = channel.accept();
                    sc.configureBlocking(false);
                    //将sc注册到Selector里，设置只关注读事件 buffer在这里作为附件给予sc
                    ByteBuffer buffer = ByteBuffer.allocate(4);
                    SelectionKey scKey = sc.register(selector, 0, buffer);
                    scKey.interestOps(SelectionKey.OP_READ);
                    System.out.println(sc);
                }else if (key.isReadable()) {
                    try{
                        SocketChannel channel = (SocketChannel) key.channel();
                        //从Key中获取ByteBuffer
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        int read = channel.read(buffer);
                        if (read == -1){
                            key.cancel();
                            channel.close();
                        }else {
                            split(buffer);
                            //发现buffer的position和limit一样，说明需要扩容
                            if (buffer.position() == buffer.limit()){
                                ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity()*2);
                                buffer.flip();
                                newBuffer.put(buffer);
                                key.attach(newBuffer);
                            }
                        }

                    }catch (IOException e){
                        e.printStackTrace();
                        key.cancel();
                    }
                }
                //key处理完后，要从selectionKeys里剔除
                iterator.remove();
            }
        }
    }
}
